#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future>

namespace zl
{
    namespace client
    {

        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr &)>;
            //异步响应类型
            using AsyncRespones = std::future<BaseMessage::ptr>;


            struct RequestDescride
            {
                using ptr = std::shared_ptr<RequestDescride>;
                BaseMessage::ptr m_req;//请求
                RType m_rtype;
                std::promise<BaseMessage::ptr> response;//异步响应
                RequestCallback m_callback;
            };

            //处理从服务器接收到的响应消息
            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
            {
                std::string rid = msg->rid();
                RequestDescride::ptr rdp = getDescride(rid);
                if (rdp.get() == nullptr)
                {
                    ELOG("收到响应 %s 但未找到对应请求描述", rid.c_str());
                    return;
                }

                if (rdp->m_rtype == RType::REQ_ASYNC)
                {
                    rdp->response.set_value(msg);
                }
                else if (rdp->m_rtype == RType::REQ_CALLBACK)
                {
                    if (rdp->m_callback)
                        rdp->m_callback(msg);
                }
                else
                {
                    ELOG("请求类型未知");
                }
                removeDescride(rid);
            }

            //异步
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncRespones &async_rsp)
            {
                //发送请求并返回一个 std::future 对象，用于获取异步响应
                RequestDescride::ptr rdp = newDescride(req, RType::REQ_ASYNC);
                if (rdp.get()==nullptr)
                {
                    ELOG("构造请求描述对象失败");
                    return false;
                }
                conn->send(req);
                async_rsp = rdp->response.get_future();
                return true;
            }

            //同步
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp)
            {
                //发送请求并阻塞等待响应
                AsyncRespones rsp_future;
                bool ret = send(conn, req, rsp_future);
                if (ret)
                {
                    rsp = rsp_future.get();
                    return true;
                }
                return false;
            }

            //回调
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, const RequestCallback &callback)
            {
                //发送请求并指定回调函数处理响应
                RequestDescride::ptr rdp = newDescride(msg, RType::REQ_CALLBACK,callback);
                if (rdp.get()==nullptr)
                {
                    ELOG("构造请求描述对象失败");
                    return false;
                }
                conn->send(msg);
                return true;
            }

        private:
            // 增
            RequestDescride::ptr newDescride(const BaseMessage::ptr &msg, RType type, const RequestCallback &callback = RequestCallback())
            {
                std::unique_lock<std::mutex> lock(m_mutex);

                RequestDescride::ptr rd = std::make_shared<RequestDescride>();
                rd->m_req = msg;
                rd->m_rtype = type;
                if (type == RType::REQ_CALLBACK && callback)
                {
                    rd->m_callback = callback;
                }

                m_request_desc[msg->rid()] = rd;
                return rd;
            }

            // 查
            RequestDescride::ptr getDescride(const std::string &id)
            {
                std::unique_lock<std::mutex> lock(m_mutex);

                auto it = m_request_desc.find(id);
                if (it == m_request_desc.end())
                {
                    return RequestDescride::ptr();
                }

                return it->second;
            }

            // 删
            void removeDescride(const std::string &id)
            {
                std::unique_lock<std::mutex> lock(m_mutex);

                m_request_desc.erase(id);
            }

        private:
            std::mutex m_mutex;
            // id 请求
            std::unordered_map<std::string, RequestDescride::ptr> m_request_desc;
        };
    }

}
